﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.XPath;
using System.IO;

namespace GateExtractor
{

    class NessAttrs
    {
        public string sem;
        public string q;
        public string dom;


    }

    class Processor
    {

        //per file stats:
        Dictionary<string, NessAttrs> rules = new Dictionary<string, NessAttrs>();

        public void Process()
        {
            Console.WriteLine("GateExtractor 0.3");
            DateTime dt_start = DateTime.Now;

            //global init
            //load jape rules
            TextReader tr = new StreamReader("n.jape");
            string line;
            string[] tokens = { "" };
            while ((line = tr.ReadLine()) != null)
            {
                //Console.WriteLine(line);
                if (line.Contains("=~")) //lhs tokens 
                {
                    string strToks = line.Substring(17, line.Length - 19);
                    tokens = strToks.Split('|');

                }
                if (line.Contains(":") && line.Contains("=") && line.Contains("sem")) // rhs or actions
                {
                    //Console.WriteLine("rhs found-------------------");
                    string strActions = line.Remove(0, line.IndexOf('{') + 1);
                    strActions = strActions.Remove(strActions.Length - 1, 1);
                    string[] actToks = strActions.Split(',');
                    NessAttrs nessAttrs = new NessAttrs();
                    foreach (string tok in actToks)
                    {
                        string key = tok.Split('=')[0].Trim().ToLower();
                        string val = tok.Split('=')[1].Trim().Trim('"'); ;
                        if (key == "sem") nessAttrs.sem = val;
                        if (key == "dom") nessAttrs.dom = val;
                        if (key == "q") nessAttrs.q = val;
                        //Console.WriteLine(tok.Trim());
                    }
                    //filline toks dictionary
                    foreach (string tok in tokens)
                    {
                        string tokTrimmed = tok.ToLower();
                        if (tok[0] == '[')
                            tokTrimmed = tok.Remove(0, 2).Remove(1, 1).ToLower();
                        if (rules.ContainsKey(tokTrimmed))
                        {
                            Console.WriteLine("Duplicated token: (" + nessAttrs.sem + ") " + tokTrimmed + "\t old sem=" + rules[tokTrimmed].sem);
                        }
                        else
                        {
                            rules.Add(tokTrimmed, nessAttrs);
                        }

                        //Console.WriteLine(tokTrimmed);
                    }

                }


            }

            DirectoryInfo di = new DirectoryInfo("./in");
            FileInfo[] Files = di.GetFiles();
            try
            {
                if (Directory.Exists("./out")) Directory.Delete("./out", true);
            }
            catch (Exception ex)
            {
                Console.WriteLine("./out :" + ex.Message);
            }
            try { Directory.CreateDirectory("./out"); }
            catch (Exception ex) { Console.WriteLine("./out :" + ex.Message); };

            foreach (FileInfo fi in Files)
            {
                ProcessFile(fi);
            }

        }



        void ProcessFile(FileInfo fi)
        {
            Console.WriteLine("\n\nProcessing " + fi.Name);
            int numWords = 0;
            TextWriter wr = new StreamWriter("./out/" + fi.Name + ".log");
            Dictionary<string, Dictionary<string, int>> nessGropusLocal = new Dictionary<string, Dictionary<string, int>>();
            try
            {

                XmlDocument myDoc = new XmlDocument();
                //init

                // nodesSyntaxTreeNodes = myDoc.SelectNodes("//Annotation[@Type='SyntaxTreeNode']");
                //load text
                myDoc.PreserveWhitespace = true;
                myDoc.Load(fi.FullName);
                Console.WriteLine("xml loadded...");
                {
                    XmlNodeList nodes = myDoc.SelectNodes("//Node");
                    numWords = nodes.Count;
                }
                string strText = "";
                {
                    XmlNode text = myDoc.SelectSingleNode("//TextWithNodes");

                    // text.RemoveAll();
                    strText = text.InnerText;
                }
                //wr.Write(text.InnerText);
                XmlNodeList nodesDep = myDoc.SelectNodes("//Annotation[@Type='Dependency']");
                XmlNodeList nodesWordFormation = myDoc.SelectNodes("//Annotation[@Type='word-formation']");
                XmlNodeList nodesMult = myDoc.SelectNodes("//Annotation[@Type='multiple']");
                //load features
                XmlNodeList nodesNess = myDoc.SelectNodes("//Annotation[@Type='ness']");
                // XmlNodeList nodesDep = myDoc.SelectNodes("//Annotation[@Type='Dependency']");
                Console.WriteLine(nodesNess.Count.ToString() + " ness annotations selected");
                for (int i = 0; i < nodesNess.Count; i++)
                {
                    //find start|end nodes
                    // wr.WriteLine("######################################################################################################################");
                    int posStartNess = System.Convert.ToInt32(nodesNess[i].Attributes["StartNode"].Value);
                    int posEndNess = System.Convert.ToInt32(nodesNess[i].Attributes["EndNode"].Value);
                    string strNessText = strText.Substring(posStartNess, posEndNess - posStartNess).Trim().ToLower();
                    strNessText = strNessText.Trim('.');
                    strNessText = strNessText.Trim('\'');
                    strNessText = strNessText.Trim(',');
                    //nessssss replacement
                    string strNessTextLkp = strNessText.Replace("nesses","ness");
                    string strToAddAfterNess = "";
                    //-replaces
                    if (strNessTextLkp == "dulness") { strNessTextLkp = "dullness"; }
                    if (strNessTextLkp == "chearfulness") { strNessTextLkp = "cheerfulness"; }
                    if (strNessTextLkp == "barrenness") { strNessTextLkp = "bareness"; }
                    if (strNessTextLkp == "fool-hardiness") { strNessTextLkp = "foolhardiness"; }
                    if (strNessTextLkp == "plainess") { strNessTextLkp = "plainness"; }
                    if (strNessTextLkp == "finesse") { strNessTextLkp = "fineness"; }
                    if (strNessTextLkp == "fulness") { strNessTextLkp = "fullness"; }
                    if (strNessTextLkp == "aukwardness") { strNessTextLkp = "awkwardness"; }
                    if (strNessTextLkp == "licenticiousness") { strNessTextLkp = "licentiousness"; }
                    if (strNessTextLkp == "happinesss") { strNessTextLkp = "happiness"; }
                    if (strNessTextLkp == "forlorness") { strNessTextLkp = "forlornness"; }
                    if (strNessTextLkp == "sterness") { strNessTextLkp = "sternness"; }
                    if (strNessTextLkp == "denderness") { strNessTextLkp = "tenderness"; }
                    if (strNessTextLkp == "businesslike") { strNessTextLkp = "business like"; }
                    if (strNessTextLkp == "fearlesssness") { strNessTextLkp = "fearlessness"; }
                    if (strNessTextLkp == "sick-ness") { strNessTextLkp = "sickness"; }
                    if (strNessTextLkp == "humanness") { strNessTextLkp = "humaneness"; }
                    if (strNessTextLkp == "absentmindedness") { strNessTextLkp = "absent-mindedness"; }
                    if (strNessTextLkp == "schoolgirlishness") { strNessTextLkp = "school-girlishness"; }
                    if (strNessTextLkp == "busyness") { strNessTextLkp = "business"; }
                    if (strNessTextLkp == "single-mindedness") { strNessTextLkp = "singlemindedness"; }
                    if (strNessTextLkp == "twofacedness") { strNessTextLkp = "two-facedness"; }
                    if (strNessTextLkp == "willfulness") { strNessTextLkp = "wilfulness"; }
                    //----hyphen
                    if (strNessTextLkp == "bitterness-a") { strNessTextLkp = "bitterness"; strToAddAfterNess = "-a"; }
                    if (strNessTextLkp == "stiffness-a") { strNessTextLkp = "stiffness"; strToAddAfterNess = "-a"; }
                    if (strNessTextLkp == "weakness-especially") { strNessTextLkp = "weakness"; strToAddAfterNess = "-especially"; }
                    if (strNessTextLkp == "grotesqueness-") { strNessTextLkp = "grotesqueness"; strToAddAfterNess = "-"; }
                    if (strNessTextLkp == "happiness-the") { strNessTextLkp = "happiness"; strToAddAfterNess = "-the"; }
                    if (strNessTextLkp == "kindness-as") { strNessTextLkp = "kindness"; strToAddAfterNess = "-as"; }
                    if (strNessTextLkp == "business-that") { strNessTextLkp = "business"; strToAddAfterNess = "-that"; }
                    if (strNessTextLkp == "awkwardness-sitting") { strNessTextLkp = "awkwardness"; strToAddAfterNess = "-sitting"; }
                    if (strNessTextLkp == "kindness-in") { strNessTextLkp = "kindness"; strToAddAfterNess = "-in"; }
                    if (strNessTextLkp == "dreariness-") { strNessTextLkp = "dreariness"; strToAddAfterNess = "-"; }
                    if (strNessTextLkp == "business-man") { strNessTextLkp = "business"; strToAddAfterNess = "-man"; }
                    if (strNessTextLkp == "businessmen") { strNessTextLkp = "business"; strToAddAfterNess = "men"; }
                    if (strNessTextLkp == "businessman") { strNessTextLkp = "business"; strToAddAfterNess = "man"; }
                    if (strNessTextLkp == "business-men") { strNessTextLkp = "business"; strToAddAfterNess = "-men"; }
                    if (strNessTextLkp == "business-like") { strNessTextLkp = "business"; strToAddAfterNess = "-like"; }
                    if (strNessTextLkp == "business-of") { strNessTextLkp = "business"; strToAddAfterNess = "-of"; }
                    if (strNessTextLkp == "business-for") { strNessTextLkp = "business"; strToAddAfterNess = "-for"; }
                    if (strNessTextLkp == "business-visits") { strNessTextLkp = "business"; strToAddAfterNess = "-visits"; }
                    if (strNessTextLkp == "business-for") { strNessTextLkp = "business"; strToAddAfterNess = "-for"; }
                    wr.WriteLine("exploring ness \"" + strNessText + "\"");



                    //print ness props
                    string carrier = "";
                    string sem = "";
                    string polarity = "";
                    bool isSemFound = false;
                    bool isNegEncountered = false;
                    foreach (XmlNode nessFeature in nodesNess[i].SelectNodes("Feature"))
                    {
                        //     wr.Write(nessFeature.SelectSingleNode("Name").InnerText + ":\t");
                        //   wr.WriteLine(nessFeature.SelectSingleNode("Value").InnerText);
                        if (nessFeature.SelectSingleNode("Name").InnerText == "carrier")
                            carrier = nessFeature.SelectSingleNode("Value").InnerText.ToLower();
                        if (nessFeature.SelectSingleNode("Name").InnerText == "qd")
                            carrier = nessFeature.SelectSingleNode("Value").InnerText.ToLower();
                        if (nessFeature.SelectSingleNode("Name").InnerText == "sem")
                        {
                            sem = nessFeature.SelectSingleNode("Value").InnerText;
                            isSemFound = true;
                        }


                        if (nessFeature.SelectSingleNode("Name").InnerText == "pol")
                            polarity = nessFeature.SelectSingleNode("Value").InnerText;

                    }

                    string strFeatureDepBonus = "";

                    //searching dep annotation with this ness
                    for (int j = 0; j < nodesDep.Count; j++)
                    {
                        int posStartDep = System.Convert.ToInt32(nodesDep[j].Attributes["StartNode"].Value);
                        int posEndDep = System.Convert.ToInt32(nodesDep[j].Attributes["EndNode"].Value);
                        if ((posEndNess >= posStartDep) && (posEndNess <= posEndDep)) //can be missing
                        {
                            string strDepText = strText.Substring(posStartDep, posEndDep - posStartDep);
                            wr.WriteLine("dependency: ");
                            //wr.WriteLine(nodesDep[j].OuterXml);
                            XmlNodeList features = nodesDep[j].SelectNodes("Feature");
                            string kind = features[1].SelectSingleNode("Value").InnerText;
                            wr.WriteLine("kind: " + kind);
                            if (kind == "det")
                            {
                                if (strDepText[0] == 'a') kind = kind + "[a]";
                                else kind = kind + "[the]";
                            }
                            if (kind == "neg")
                            {
                                isNegEncountered = true;
                            }
                            strFeatureDepBonus += "<Feature>\n" +
                            "\t<Name className=\"java.lang.String\">" + kind + "</Name>\n" +
                            "\t<Value className=\"java.lang.String\">+</Value>\n" +
                            "</Feature>\n";
                            wr.WriteLine("text: " + strDepText);

                            //string args = features[0].SelectSingleNode("Value").InnerText;
                            //string[] argTokens = args.Split(';');

                            /// wr.Write("args: " );
                            // foreach (string arg in argTokens)
                            //    PrintSyntaxTreeNode(System.Convert.ToInt32(arg),wr);

                            //wr.WriteLine("\n");
                            //find arguments
                            //wr.WriteLine(nodesDep[j].OuterXml);
                        }
                    }
                    //searching word-formation annotation with this ness
                    bool isWFFound = false;
                    foreach (XmlNode cursor in nodesWordFormation)
                    {
                        int posStartDep = System.Convert.ToInt32(cursor.Attributes["StartNode"].Value);
                        int posEndDep = System.Convert.ToInt32(cursor.Attributes["EndNode"].Value);
                        if ((posEndNess >= posStartDep) && (posEndNess <= posEndDep)) //can be missing
                        {
                            string strDepText = strText.Substring(posStartDep, posEndDep - posStartDep);
                            wr.WriteLine("WF: ");
                            if (!isWFFound)
                            {
                                strFeatureDepBonus += "<Feature>\n" +
                                "\t<Name className=\"java.lang.String\">xWF</Name>\n" +
                                "\t<Value className=\"java.lang.String\">+</Value>\n" +
                                "</Feature>\n";
                                isWFFound = true;
                            }
                        }
                    }
                    //searching multiple annotation with this ness
                    bool isMultFound = false;
                    foreach (XmlNode cursor in nodesMult)
                    {
                        int posStartDep = System.Convert.ToInt32(cursor.Attributes["StartNode"].Value);
                        int posEndDep = System.Convert.ToInt32(cursor.Attributes["EndNode"].Value);
                        if ((posEndNess >= posStartDep) && (posEndNess <= posEndDep)) //can be missing
                        {
                            string strDepText = strText.Substring(posStartDep, posEndDep - posStartDep);
                            wr.WriteLine("Multiple: ");
                            if (!isMultFound)
                            {
                                strFeatureDepBonus += "<Feature>\n" +
                                "\t<Name className=\"java.lang.String\">xTheme</Name>\n" +
                                "\t<Value className=\"java.lang.String\">+</Value>\n" +
                                "</Feature>\n";
                                isMultFound = true;
                            }
                        }
                    }


                    if (!isSemFound)
                    {

                        wr.WriteLine("no sem feature, inserting");
                        NessAttrs newAttrs;
                        if (rules.ContainsKey(strNessTextLkp))
                        {
                            newAttrs = rules[strNessTextLkp];
                        }
                        else
                        {
                            Console.WriteLine("No rule found for \"" + strNessText + "\" (" + strNessTextLkp + ")");
                            newAttrs = rules["xxxxx"];
                        }
                        

                        string newGrad = newAttrs.q;
                        //!!!!!!!!!!!!!! reverse grad !!!!!!!!!!!!!!!!!!!!!1
                        if (isNegEncountered)
                        {
                            newGrad = (2 - System.Convert.ToInt32(newAttrs.q)).ToString();

                           // Console.WriteLine("neg - reversing grad");
                        }
                        if (System.Convert.ToInt32(newGrad) < 0)
                        {
                            Console.WriteLine(strNessText + "  grad below zero!!!!!");
                            wr.WriteLine(strNessText + "  grad below zero!!!!!");
                        }
                        string newNode = "<Feature>\n" +

                        "\t<Name className=\"java.lang.String\">_carrier</Name>\n" +
                        "\t<Value className=\"java.lang.String\"></Value>\n" +
                        "</Feature>\n" +
                        "<Feature>\n" +
                        "\t<Name className=\"java.lang.String\">_grad</Name>\n" +
                        "\t<Value className=\"java.lang.String\">" + newGrad + "</Value>\n" +
                        "</Feature>\n" +
                        "<Feature>\n" +
                        "\t<Name className=\"java.lang.String\">_sem</Name>\n" +
                        "\t<Value className=\"java.lang.String\">" + newAttrs.sem + "</Value>\n" +
                        "</Feature>\n" +
                        "<Feature>\n" +
                        "\t<Name className=\"java.lang.String\">_dom</Name>\n" +
                        "\t<Value className=\"java.lang.String\">" + newAttrs.dom + "</Value>\n" +
                        "</Feature>\n" + strFeatureDepBonus +
                        "<Feature>\n" +
                        "\t<Name className=\"java.lang.String\">string</Name>\n" +
                        "\t<Value className=\"java.lang.String\">" + strNessText + "</Value>\n" +
                        "</Feature>\n";
                        nodesNess[i].InnerXml = newNode;

                     

                           
                    


                    }
                    else
                    {
                        Console.WriteLine("already has sem annotation");
                    }

                    wr.WriteLine();


                }//end processing nesses
                myDoc.Save("./out/" + fi.Name);


            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }


            wr.Close();



        }// end processfile
    }

}
